﻿/******************************************************************************************
 
Made by www.Flashphoner.com, all rights reserved.
These sources can only be used for working with Flashphoner server.
If you want use this to create your own application (separate from Flashphoner server) – 
please contact support@flashphoner.com 

******************************************************************************************/

package com.flashphoner.api
{
	import com.flashphoner.api.data.ErrorCodes;
	import com.flashphoner.api.data.ModelLocator;
	import com.flashphoner.api.data.PhoneConfig;
	import com.flashphoner.api.interfaces.API;
	import com.flashphoner.api.interfaces.APINotify;
	import com.flashphoner.api.js.APINotifyJS;
	import com.flashphoner.api.management.PhoneSpeaker;
	import com.flashphoner.api.management.SoundControl;
	import com.flashphoner.api.management.VideoControl;
	
	import flash.events.TimerEvent;
	import flash.external.ExternalInterface;
	import flash.media.Camera;
	import flash.media.Microphone;
	import flash.net.Responder;
	import flash.utils.Timer;
	
	import mx.collections.ArrayCollection;

	[Bindable]
	public class Flash_API
	{
		private var registeredTimer:Timer;
		/**
		 * @private
		 **/
		internal var phoneServerProxy:PhoneServerProxy;
		/**
		 * List of calls
		 **/
		public var calls:ArrayCollection;	
		/**
		 * @private
		 * Notifier added by addNotify()
		 **/ 
		internal var apiNotify:APINotify;		
		/**
		 * Data about logged user
		 **/
		public var modelLocator:ModelLocator;
		
		/**
		 *
		 * Initialize parameters from 'flashphoner.xml' and another 
		 **/
		public static function initLibrary():void{
			PhoneModel.getInstance();
		}
		/**
		 * Default contructor.
		 * Initialize calls,modelLocato and initialize library
		 */		
		public function Flash_API(){
			PhoneModel.getInstance();
			calls = new ArrayCollection();
			modelLocator = new ModelLocator();
			phoneServerProxy = new PhoneServerProxy(new Responder(result),this);
		}
		
		/**
		 * Get current call in TALK-state
		 **/
		public function getCurrentCall():Call{
			for each(var obj:* in calls){
				if (obj.state == Call.STATE_TALK){
					return Call(obj);	
				}
			}
			return null;
		}
			
		/**
		 * Get call by indetifier
		 * @param callId Identifier of call
		 **/
		public function getCallById(callId:String):Call{
			for each(var obj:* in calls){
				if (obj.id == callId){
					return Call(obj);
				}
			}
			return null;
		}

		/**
		 * Get call by index 
		 * @param index Index in calls collection
		 **/		
		public function getCallByIndex(index:Number):Call{
			var obj:* = calls.getItemAt(index);
			if (obj != null){
				return Call(obj);	
			}
			return null;
		}	
		
		/**
		 * Get index by call identifier 
		 * @param callId Identifier of call 
		 * @return -1 - if call not found
		 **/		
		public function getIndexByCallId(callId:String):Number{
			for (var index:* in calls){
				var obj:* = calls.getItemAt(index);
				if (obj.id == callId){
					return index;
				}
			}
			return -1;
		}	
		
		/**
		 * @private
		 * Add call to calls collection
		 **/
		internal function addCall(call:Call):void{
			for (var index:* in calls){
				var obj:* = calls.getItemAt(index);
				if (obj.id == call.id){
					return;
				}
			}
			calls.addItem(call);
		}
		/**
		 * @private
		 * Remove call from calls collection
		 * @param callId Identifier of call
		 **/
		internal function removeCall(callId:String):void{
			for (var index:* in calls){
				var obj:* = calls.getItemAt(index);
				if (obj.id == callId){
					calls.removeItemAt(index);
				}
			}
		}
		
		/**
		 * Get controller of speaker
		 **/		
		public function getPhoneSpeaker():PhoneSpeaker{
			return this.phoneServerProxy.phoneSpeaker;
		}

		/**
		 * Add notifier to api
		 * @param apiNotify Object will be implemented APINotify
		 **/
		public function addAPINotify(apiNotify:APINotify):void{
			this.apiNotify = apiNotify;
		}
		/**
		 * Get parameters from file 'flashphoner.xml'
		 **/
		public function getParameters():Object{
			var object:Object = PhoneModel.getInstance().parameters;
			if (object == null){
				return ErrorCodes.PARAMETERS_IS_NOT_INITIALIZED;				
			}else{
				return PhoneModel.getInstance().parameters;
			}
		}
		/**
		 * Authentication on sip provider server on "flashphoner" mode
		 * @param username sip format username (example: sip:...)
		 * @param password Password for user
		 **/
		public function login(username:String,password:String):int{
			ExternalInterface.call("notifyRegisterRequired",PhoneConfig.REGISTER_REQUIRED);
			if (PhoneConfig.REGISTER_REQUIRED){
				upRegisteredTimer();
				startRegisterTimer();
			}
			return phoneServerProxy.login(username,password);							
		}
		
		public function loginWithToken(token:String):int{
			ExternalInterface.call("notifyRegisterRequired",PhoneConfig.REGISTER_REQUIRED);
			if (PhoneConfig.REGISTER_REQUIRED){
				upRegisteredTimer();
				startRegisterTimer();
			}
			return phoneServerProxy.loginWithToken(token);							
		}		
		/**
		  * Authentication on sip provider server on "click2call" mode
		  * Data of user will be on server in file 'flashphoner.properties'
		  **/
		public function loginClick2Call():void{
			ExternalInterface.call("notifyRegisterRequired",PhoneConfig.REGISTER_REQUIRED);
			if (PhoneConfig.REGISTER_REQUIRED){
				upRegisteredTimer();
				startRegisterTimer();
			}
			phoneServerProxy.login();							
		}
		
		/**
		 * Create new call
		 * @param callee login of user - target call
		 * @param visibleName name of logged user wich target user see
		 * @param isVideoCall video call?(true/false)
		 **/ 
		public function call(callee:String, visibleName:String, isVideoCall:Boolean = false):int{
			if (PhoneConfig.CHECK_VALIDATION_CALLEE){
				var reg:RegExp = /[a-zа-яё]/i;
				if (callee != null && callee != ""){
					if (modelLocator.mode == "flashphoner"){
						if ((callee.indexOf("sip:") == 0)){
							if (callee.indexOf("@") == -1 || callee.indexOf("@") == callee.length-1){
								return 1;
							}
						}else{
							if (callee.search(reg) != -1){
								if (callee.indexOf("@") != -1){
									return 1;
								}
								if (callee.indexOf(":") != -1){
									return 1;
								}
								callee = "sip:"+callee+"@"+modelLocator.sipProviderAddress+":"+modelLocator.sipProviderPort;
							}
						}
					}else{
						return 1;
					}
				}else{
					if (modelLocator.mode != "click2call"){
						return 1;
					}
				}
			}
			if (visibleName != null){
				visibleName.replace("\"","");
				visibleName.replace("\'","");
			}
			for each (var tempCall:Call in calls){
				if (tempCall.state == Call.STATE_TALK){
					tempCall.setStatusHold(true);
				}
			}
			phoneServerProxy.call(visibleName,callee,isVideoCall);
			return 0;
		}		
		
		/**
		 * Get volume of current microphone
		 * @return volume interval 1-100
		 **/
		public function getMicVolume():int{
			return SoundControl.getInstance().getMicrophone().gain;
		}
		
		/**
		 * Set volume for current microphone
		 * @param volume interval 1-100
		 **/
		public function setMicVolume(volume:int):void{
			SoundControl.getInstance().getMicrophone().gain = volume;
		}
		
		/**
		 * Get volume of speakers
		 * @return volume interval 1-100
		 **/
		public function getVolume():int{
			return phoneServerProxy.phoneSpeaker.getVolume();
		}
		
		/**
		 * Set volume for speakers
		 * @param volume interval 1-100
		 **/
		public function setVolume(volume:int):void{
			phoneServerProxy.phoneSpeaker.setVolume(volume);
		}
		
		/**
		 * Get list of microphones
		 **/
		public function getMicropones():Array{
			return Microphone.names;
		}
		
		/**
		 * Set current microphone
		 * @param name name of microphone
		 **/
		public function setMicrophone(name:String):void{
			var i:int = 0;
			for each (var nameMic:String in Microphone.names){
				if (nameMic == name){
					SoundControl.getInstance().changeMicrophone(Microphone.getMicrophone(i),false);
					return;						
				}
				i++;				
			}
		}
		/**
		 * Get list of cameras
		 **/
		public function getCameras():Array{
			return Camera.names;
		}
		
		/**
		 * Set current camera
		 * @param name name of camera
		 **/		
		public function setCamera(name:String):void{
			VideoControl.getInstance().changeCamera(Camera.getCamera(name));
		}
		/**
		 * Log off from the server and close connection
		 **/
		public  function logoff():void{
			phoneServerProxy.disconnect();
		}
		/**
		 * @private
		 **/
		internal function startRegisterTimer():void{
			registeredTimer.start();	
		}
		
		
		/**
		 * @private
		 * Start timer for REGISTER_EXPIRE error
		 **/
		internal function upRegisteredTimer():void{
			if (registeredTimer!=null){
				registeredTimer.stop();
			} else {
				registeredTimer = new Timer(13000);
				registeredTimer.addEventListener(TimerEvent.TIMER,registeredExpire);					
			}
		}
		
		/**
		 * @private
		 * Stop timer for REGISTER_EXPIRE error 
		 **/
		internal function dropRegisteredTimer():void{
			if (registeredTimer!=null){
				registeredTimer.stop();
				registeredTimer.removeEventListener(TimerEvent.TIMER,registeredExpire);
				registeredTimer=null;
			}
		}
		
		/**
		 * Handler on registerTimer
		 **/
		private function registeredExpire(event:TimerEvent):void{
			apiNotify.notifyError(ErrorCodes.REGISTER_EXPIRE);			
			dropRegisteredTimer();			
		}			
		/**
		 * Impementation for Responder
		 **/  
		private function result(_call : Object) : void
		{
			var call:Call = new Call(this);
			call.id = _call.id;
			call.state = _call.state;
			call.incoming=false;							
			addCall(call);
		}		
		

	}
}